// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;

namespace ILLink.RoslynAnalyzer
{
    internal static class INamedTypeSymbolExtensions
    {
        /// <summary>
        /// Returns true if <see paramref="type" /> has the same name as <see paramref="typename" />
        /// </summary>
        internal static bool HasName(this INamedTypeSymbol type, string typeName)
        {
            var roSpan = typeName.AsSpan();
            INamespaceOrTypeSymbol? currentType = type;
            while (roSpan.Length > 0)
            {
                var dot = roSpan.LastIndexOf('.');
                var currentName = dot < 0 ? roSpan : roSpan.Slice(dot + 1);
                if (currentType is null ||
                    !currentName.Equals(currentType.Name.AsSpan(), StringComparison.Ordinal))
                {
                    return false;
                }
                currentType = (INamespaceOrTypeSymbol?)currentType.ContainingType ?? currentType.ContainingNamespace;
                roSpan = roSpan.Slice(0, dot > 0 ? dot : 0);
            }

            return true;
        }

        internal static IEnumerable<(ISymbol InterfaceMember, ISymbol ImplementationMember)> GetMemberInterfaceImplementationPairs(this INamedTypeSymbol namedType)
        {
            var interfaces = namedType.Interfaces;
            foreach (INamedTypeSymbol iface in interfaces)
            {
                foreach (var pair in GetMatchingMembers(namedType, iface))
                {
                    yield return pair;
                }
            }
        }

        private static IEnumerable<(ISymbol InterfaceMember, ISymbol ImplementationMember)> GetMatchingMembers(INamedTypeSymbol implementationSymbol, INamedTypeSymbol interfaceSymbol)
        {
            var members = interfaceSymbol.GetMembers();
            foreach (ISymbol interfaceMember in members)
            {
                if (implementationSymbol.FindImplementationForInterfaceMember(interfaceMember) is ISymbol implementationMember)
                {
                    yield return (InterfaceMember: interfaceMember, ImplementationMember: implementationMember);
                }
            }
            foreach (var iface in interfaceSymbol.Interfaces)
            {
                foreach (var pair in GetMatchingMembers(implementationSymbol, iface))
                {
                    yield return pair;
                }
            }
        }
    }
}
